<?
import('japha.io.StringWriter');
import('japha.io.PrintWriter');

/**
 * A <code>TestFailure</code> collects a failed test together with
 * the caught exception.
 *
 * @see TestResult
 * @author Ryan Gantt
 */
class TestFailure extends Object
{
	/**
	 * The instance of test that failed
	 *
	 * @type Test
	 */
	protected $fFailedTest;

	/**
	 * The exception that was thrown when the test failed
	 *
	 * @type Test
	 */
	protected $fThrownException;

	/**
	 * Constructs a TestFailure with the given test and exception.
	 *
	 * @param failedTest The instance of Test that failed the assertions
	 * @param thrownException The exception that was thrown due to the Test instance failing
	 */
	public function __construct( Test $failedTest, Throwable $thrownException )
	{
		$this->fFailedTest = $failedTest;
		$this->fThrownException = $thrownException;
	}

	/**
	 * Gets the failed test.
	 *
	 * @return Test The instance of Test that failed the assertions
	 */
	public function failedTest()
	{
		return $this->fFailedTest;
	}

	/**
	 * Gets the thrown exception.
	 *
	 * @return Throwable The exception that was thrown in response to the Test instance failing
	 */
	public function thrownException()
	{
		return $this->fThrownException;
	}

	/**
	 * Returns a short description of the failure.
	 *
	 * @return string A short description of the failure, which comes from the exception
	 */
	public function toString()
	{
		$buffer = new StringBuffer();
		$buffer->append( $this->fFailedTest.': '.$this->fThrownException->getMessage() );
		return $buffer->toString();
	}

	/**
	 * Forces the appropriate abstracted calls in order to print a stack trace of the exception(s). Forces the
	 * throwable class to put the stack trace information into an object instead of printing it to the screen
	 *
	 * @return string String representation of the stack trace
	 */
	public function trace()
	{
		$stringWriter = new StringWriter();
		$writer = new PrintWriter( $stringWriter );
		$this->thrownException()->printStackTrace( $writer );
		$buffer = $stringWriter->getBuffer();
		return $buffer->toString();
	}

	/**
	 * Returns the detail message from the Throwable in the class instance
	 *
	 * @return string The detail message from the exception
	 */
	public function exceptionMessage()
	{
		return $this->thrownException()->getMessage();
	}

	/**
	 * Figures out whether or not the instance Throwable is an instance of AssertionFailedError
	 *
	 * @return boolean True if the instance Throwable is an instance of AssertionFailedError
	 */
	public function isFailure()
	{
		return ( $this->thrownException() instanceof AssertionFailedError );
	}
}